#include "libgenbank.h"
#include "libfasta.h"

int icmpr(const void *lhs, const void *rhs)
{
    return ((struct interval *)lhs)->begin - ((struct interval *)rhs)->begin;
}

struct interval *get_interval(const char *file_name, int num)
{
    //    char temp_file[] = "suppCDSfile.tmp";
    //    {
    //        char cmd[100] = "cat ";
    //        strcat(cmd, file_name);
    //        strcat(cmd, " | grep -P '^ +CDS.*' > ./");
    //        strcat(cmd, temp_file);
    //        system(cmd);
    //    }
    int kind = 0, bracket = 0, innumber = 0;
    struct interval *intervals = (struct interval *)malloc(num * sizeof(struct interval));

    for (int i = 0; i < num; ++i)
    {
        intervals[i].begin = intervals[i].end = intervals[i].compl = 0;
    }
    char buffer[1024];
    FILE *CDS_info;
    if ((CDS_info = fopen(file_name, "r")) == NULL)
    {
        perror("fail to read");
        exit(1);
    }
    while (fgets(buffer, 1024, CDS_info) != NULL)
        if (strstr(buffer, "FEATURES") != NULL)
        {
            while (innumber < num)
            {
                if (strstr(buffer, "   CDS    "))
                {
                    int space = 0, compl = 0, length = strlen(buffer);
                    do
                    {
                        for (int i = 0; i < length; ++i)
                        {
                            if (!space && buffer[i] == 'S')
                                ++space;
                            else if (buffer[i] != ' ')
                                if (buffer[i] == 'c')
                                    compl = bracket + 1;
                                else if (buffer[i] == '(')
                                    ++bracket;
                                else if (buffer[i] == ')')
                                    --bracket;
                                else if (buffer[i] == '.')
                                {
                                    int j = i - 1;
                                    buffer[i] = '\0';
                                    intervals[innumber].counter = innumber;
                                    intervals[innumber].name = NULL;
                                    intervals[innumber].compl = (compl != 0 && compl <= bracket);
                                    while (buffer[j] >= '0' && buffer[j] <= '9')
                                        --j;
                                    intervals[innumber].begin = atoi(buffer + j + 1);
                                    j = i + 2;
                                    while (buffer[j] >= '0' && buffer[j] <= '9')
                                        ++j;
                                    char tmpch = buffer[j];
                                    buffer[j] = '\0';
                                    i += 2;
                                    intervals[innumber].end = atoi(buffer + i);
                                    buffer[j] = tmpch;
                                    i = j - 1;
                                    intervals[innumber].kind = kind;
                                    ++innumber;
                                }
                        }
                        fgets(buffer, 1024, CDS_info);
                        length = strlen(buffer);
                    } while (bracket);
                    ++kind;
                }
                else
                {
                    fgets(buffer, 1024, CDS_info);
                    continue;
                }
                for (int k = 0; k < strlen(buffer); ++k)
                    if (buffer[k] == '"')
                    {
                        int i = ++k;
                        while (buffer[++i] != '"')
                            ;
                        buffer[i] = '\0';
                        intervals[innumber - 1].name = (char *)malloc(sizeof(char) * (i + 1 - k));
                        strcpy(intervals[innumber - 1].name, buffer + k);
                        fgets(buffer, 1024, CDS_info);
                        break;
                    }
            }
            break;
        }
        else
            continue;
    fclose(CDS_info);
    return intervals;
}

int interval_number(const char *temp_file)
{
    char buffer[1024];
    FILE *CDS_info;

    if ((CDS_info = fopen(temp_file, "r")) == NULL)
    {
        perror("fail to read");
        exit(1);
    }
    int innumber = 0, bracket = 0;
    while (fgets(buffer, 1024, CDS_info) != NULL)
        if (strstr(buffer, "FEATURES") != NULL)
        {
            while (strstr(buffer, "ORIGIN") == NULL)
            {
                if (strstr(buffer, "   CDS    "))
                {
                    int space = 0;
                    do
                    {
                        for (int i = 0; i < strlen(buffer); ++i)
                        {
                            if (!space && buffer[i] == 'S')
                                ++space;
                            else if (buffer[i] != ' ')
                                if (buffer[i] == '(')
                                    ++bracket;
                                else if (buffer[i] == ')')
                                    --bracket;
                                else if (buffer[i] == '.')
                                    ++innumber;
                        }
                        fgets(buffer, 1024, CDS_info);
                    } while (bracket);
                }
                else
                    fgets(buffer, 1024, CDS_info);
            }
            break;
        }
        else
            continue;
    return innumber / 2;
}

struct sequence *read_seq(char *file_name)
{
    int n = interval_number(file_name);
    struct interval *intervals = get_interval(file_name, n);

    qsort(intervals, n, sizeof(struct interval), icmpr);
    struct sequence *sequences = (struct sequence *)malloc(n * sizeof(struct sequence));
    for (int j = 0; j < n; ++j)
    {
        sequences[intervals[j].counter].kind = intervals[j].kind;
        sequences[intervals[j].counter].name = intervals[j].name;
        sequences[intervals[j].counter].compl = intervals[j].compl;
        sequences[j].seq = "";
        sequences[j].length = 0;
    }

    //    for (int j = 0; j < n; ++j) {
    //        if (sequences[j].name)
    //         printf("%s\n", sequences[j].name);
    //        printf("%d, %d\n", sequences[j].kind);
    //    }
    char buffer[1024];
    FILE *CDS_info;

    if ((CDS_info = fopen(file_name, "r")) == NULL)
    {
        perror("fail to read");
        exit(1);
    }
    while (fgets(buffer, 1024, CDS_info) != NULL)
    {
        buffer[6] = '\0';
        if (strcmp(buffer, "ORIGIN") == 0)
        {
            fgets(buffer, 1024, CDS_info);
            while (buffer[0] != '/')
            {
                int num = atoi(buffer);
                int pos = 0;
                for (int i = pos; i < n; ++i)
                {
                    if (num >= intervals[i].begin)
                        if (num > intervals[i].end)
                            ++pos;
                        else
                        {
                            int buflen = strlen(buffer);
                            int *seqlen = &sequences[intervals[i].counter].length;
                            char *tmp = sequences[intervals[i].counter].seq;
                            char *seq = sequences[intervals[i].counter].seq = (char *)malloc(
                                *seqlen + buflen + 1);
                            strcpy(seq, tmp);
                            strcat(seq, buffer);
                            if (*seqlen)
                                free(tmp);
                            *seqlen += strlen(buffer);
                        }
                    else
                        continue;
                }
                fgets(buffer, 1024, CDS_info);
            }
            break;
        }
    }
    fclose(CDS_info);
    //for (int i = 0; i < n; ++i)
    //    if (intervals[i].name)
    //        free(intervals[i].name);
    free(intervals);
    for (int i = 0; i < n; ++i)
    {
        printf("%d, %d, %d\n", sequences[i].length,
               sequences[i].kind, sequences[i].compl);
        printf("%s", sequences[i].seq);
        if (sequences[i].name)
            printf("%s\n", sequences[i].name);
    }
    return sequences;
}
